/*
 * main.c
 *
 * Point d'entrée du programme de brute-forcing de chaine MD5.
 * Dans ce fichier on gère la création de threads chargés de rechercher la clef
 * correspondante à un checksum md5 saisi par l'utilisateur.
 *
 * Les erreurs de saisie de l'utilisateur ne sont pas prises en compte.
 *
 *  Created on: Feb 28, 2010
 *      Author: vtellier
 */

#include <stdio.h>				// Entrées sorties standards
#include <stdlib.h>				// Pour les allocations dynamiques
#include <pthread.h>			// Librairie des threads POSIX
#include <time.h>		// Pour chronométrer le temps de brute-forcing
#include "lib/bruteforce.h"		// Les définitions de types pour nos recherches.
#include "lib/Simple.h"			// Algorithme de craquage simple
#include "lib/multithread.h"	// Librairie dédiée à la recherche par multi-threading

// md5("abc")	= 900150983cd24fb0d6963f7d28e17f72
// md5("5")		= e4da3b7fbbce2345d7772b0674a318d5
// md5("abc0)	= 577571be4de9dcce85a041ba0410f29f

// Globales

// La liste des caractères que l'on utilisera dans les combinaisons.
// L'ordre doit suivre celui de la table ASCII
char charset[63] = "abcde";
//char charset[63] = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";

void multith_simple(char * checksum, int * max_length);
void monoth_simple(char * checksum, int * max_length);

int main()
{
	int		choix_menu = -1;
	char	checksum[33];
	int		max_length;

	// On vide la console
	printf("%c[2J", 0x1B);

	// On entre dans la boucle du menu.
	while(choix_menu != 0)
	{
		// On vide la console
//		printf("%c[2J", 0x1B);

		if(choix_menu != -1)
			printf("Refaites votre choix :\n\n");

		// Affichage du menu
		printf("\t+----------------- Menu -----------------+\n");
		printf("\t| 1 Algorithme simple                    |\n");
		printf("\t| 2 Multi-threading simple               |\n");
		printf("\t| 0 Quitter                              |\n");
		printf("\t|                                        |\n");
		printf("\t|                    Not legal for crack |\n");
		printf("\t+----------------------------------------+\n");
		printf("\t\tVotre choix : ");

		// Saisie du choix
		scanf("%d", &choix_menu);

		if(choix_menu == 0)
			continue;

		// Demande de saisie du checksum
		printf("Veuillez saisir le checksum md5 à cracker : ");
		scanf("%s",checksum);

		printf("Taille maximale de la clef : ");
		scanf("%d", &max_length);

		// Interprétation de la saisie
		switch(choix_menu)
		{
		case 1:	// Lancement de l'algorithme simple
			monoth_simple(checksum, &max_length);
		break;
		case 2:	// Lancement du multi-threading
			multith_simple(checksum, &max_length);
		break;
		}
	}

	printf("Merci, à plus.\n\n");

	return 0;
}


void monoth_simple(char * checksum, int * max_length)
{
	t_bruteforce params;
	clock_t	start = clock(); // Récupération de la date de départ
	clock_t	end;
	pthread_mutex_t my_mutex;
	char *	resultat;
	char * init = (char *) malloc(*max_length * sizeof(char));

	init[0] = charset[0];
	init[1] = '\0';

	params.checksum			= checksum;
	params.jump				= 0;	// Inutil, mais permet d'assurer d'avoir un type entier.
	params.max_length		= *max_length;
	params.value_at_start	= init;
	params.competitors		= (pthread_t *) malloc(sizeof(pthread_t));
	*(params.competitors)	= (pthread_t) 0; // Aucun thread concurrent
	params.mutal_ex			= my_mutex;
	params.charset			= charset;

	// Initialisation du mutex (pour rien)
	pthread_mutex_init(&my_mutex, NULL);

	// Lancement de la recherche :
	resultat = (char *) AlgoSimple((void *) &params);

	// Destruction du mutex
	pthread_mutex_destroy(&my_mutex);

	// Récupération de la date de fin de recherche.
	end = clock();

	if(resultat[0] == '\0')
		printf("La recherche à été terminée mais n'a abouti à aucun resultat.\n");
	else
		printf("Chaine trouvé : \"%s\"\n", resultat);

	// Affichage du temps de recherche
	printf("Temps de brute-forcing : %f\n",((double)end-start)/CLOCKS_PER_SEC);
}

void multith_simple(char * checksum, int * max_length)
{
	t_bruteforce params;

	// DE LA
	char *	init	= (char *)	malloc(*max_length * sizeof(char));
	int *	ch_init	= (int *)	malloc(*max_length * sizeof(int));

	init[0] = charset[0];
	init[1] = '\0';
	// A LA ===> LE FAIRE DANS LES THREADS EUX-MÊME


	params.checksum			= checksum;
	params.jump				= 0;	// Inutil, mais permet d'assurer d'avoir un type entier.
	params.max_length		= *max_length;
	params.value_at_start	= init;
	params.ch_index			= ch_init;
	params.charset			= charset;

	// Lancement de la recherche :
	start_multithread(params, AlgoSimple);
//	free(init);
//	free(ch_init);
}
